﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Drawing;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Net.NetworkInformation;

#region Copyright (C) 2010 Null Studio
/*
 * Author:Null hetaoos@gmail.com
 * Blog: http://blog.hetaoos.com
 * Copyright (C) 2010 Null Studio
 * 
 * 
 * PACMaker is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * PACMaker is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with PACMaker. If not, see <http://www.gnu.org/licenses/>.
 */
#endregion

namespace com.hetaoos.PacMaker.Utils
{
    public class HttpHelper
    {
        public static string Get(Uri uri)
        {
            return Request(uri, null, 2);
        }
        public static string Get(string url)
        {
            return Request(url, null, 2);
        }

        public static string Post(Uri uri, string msg)
        {
            return Request(uri, msg, 2);
        }
        public static string Post(string url, string msg)
        {
            return Request(url, msg, 2);
        }

        private static string Request(string url, string msg, int tryTimes)
        {
            Uri uri = new Uri(url);
            return Request(uri, msg, tryTimes);
        }

        private static string Request(Uri uri, string msg, int tryTimes)
        {

            if (string.IsNullOrEmpty(msg))
            {
                msg = string.Format(getHeader, uri.PathAndQuery, uri.Host);
            }
            else
            {
                msg = string.Format(postHeader, uri.PathAndQuery, uri.Host, Encoding.UTF8.GetByteCount(msg), msg);
            }
            TcpClient tcp = new TcpClient();
            var i = tcp.SendTimeout;
            var t = tcp.ReceiveTimeout;
            NetworkStream ns = null;
            MemoryStream ms = null;
            try
            {
                tcp.SendTimeout = tcp.ReceiveTimeout = 30000;
                tcp.Connect(uri.Host, uri.Port);
                ns = tcp.GetStream();
                var s = Encoding.UTF8.GetBytes(msg);
                ns.Write(s, 0, s.Length);
                ns.Flush();
                if (GetStateCode(ns) != 200)
                {
                    return string.Empty;
                }
                var headers = ParseHttpHeader(ns);
                ms = new MemoryStream();
                int ContentLength = 0;
                if (headers[HttpResponseHeader.ContentLength] != null)
                {
                    int.TryParse(headers[HttpResponseHeader.ContentLength], out ContentLength);
                }
                int count = 0;
                byte[] buff = new byte[10 * 1024];

                while (true)
                {
                    count = ns.Read(buff, 0, buff.Length);
                    if (count > 0)
                    {
                        ms.Write(buff, 0, count);
                    }
                    if (ns.DataAvailable == false)
                    {
                        if (ms.Length >= ContentLength)
                        {
                            break;
                        }
                        Thread.Sleep(200);
                        if (ns.DataAvailable == false)
                        {
                            break;
                        }
                    }
                }
                ms.Position = 0;
                using (StreamReader de = new StreamReader(ms))
                {
                    return de.ReadToEnd();
                }
            }
            catch (Exception ex)
            {
                if (tryTimes <= 0)
                {
                    throw ex;
                }
                else
                {
                    Thread.Sleep(2000);
                    return Request(uri, msg, --tryTimes);
                }
            }
            finally
            {
                if (ns != null)
                {
                    ns.Dispose();
                }
                if (tcp != null)
                {
                    tcp.Close();
                }
                if (ms != null)
                {
                    ms.Dispose();
                }
            }
        }

        public static Image GetImage(string url)
        {
            Uri uri = new Uri(url);
            return GetImage(uri);
        }
        public static Image GetImage(Uri uri)
        {
            //WebClient client = new WebClient();
            //client.Proxy = null;

            //var d = client.DownloadData(url);
            //MemoryStream ms = new MemoryStream(d);
            //return Image.FromStream(ms);

            string msg = string.Format(getHeader, uri.AbsolutePath, uri.Host);

            TcpClient tcp = new TcpClient();
            NetworkStream ns = null;
            //MemoryStream ms = null;
            try
            {
                tcp.SendTimeout = tcp.ReceiveTimeout = 30000;
                tcp.Connect(uri.Host, uri.Port);
                ns = tcp.GetStream();
                var s = Encoding.UTF8.GetBytes(msg);
                ns.Write(s, 0, s.Length);
                ns.Flush();
                if (GetStateCode(ns) != 200)
                {
                    return null;
                }
                var headers = ParseHttpHeader(ns);
                return Image.FromStream(ns);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                if (ns != null)
                {
                    ns.Dispose();
                }
                if (tcp != null)
                {
                    tcp.Close();
                }
                //if (ms != null)
                //{
                //    ms.Dispose();
                //}
            }
        }

        public static int GetStateCode(NetworkStream stream)
        {
            string headerLine = GetNextHeaderLine(stream);
            if (string.IsNullOrEmpty(headerLine))
            {
                return 0;
            }
            var i = headerLine.Split(' ');
            if (i.Length != 3)
            {
                return 0;
            }

            int code = 0;
            if (int.TryParse(i[1], out code))
            {
                return code;
            }
            return 0;
            //HTTP/1.1 302 Found
            //return 1;
        }

        public static WebHeaderCollection ParseHttpHeader(NetworkStream stream)
        {
            //string firstLine = GetNextHeaderLine(stream);
            WebHeaderCollection headers = new WebHeaderCollection();
            string headerLine;
            while ((headerLine = GetNextHeaderLine(stream)).Length != 0)
            {
                try
                {
                    headers.Add(headerLine);
                }
                catch { }
            }
            return headers;
        }

        private static byte[] pingData = Encoding.ASCII.GetBytes("012345678901234567890123456789");
        public static bool CanPing(string host)
        {
            try
            {
                using (Ping ping = new Ping())
                {
                    PingReply reply = ping.Send(host, 120, pingData);
                    return reply.Status == IPStatus.Success;
                }
            }
            catch
            {
                return false;
            }
        }

        public static bool CanConnect(string host)
        {
            return CanConnect(host, 80);
        }

        public static bool CanConnect(string host, int port)
        {
            bool connected = false;
            try
            {
                using (TcpClient tc = new TcpClient())
                {
                    tc.SendTimeout = tc.ReceiveTimeout = 2000;
                    tc.Connect(host, port);
                    connected = tc.Connected;
                    tc.Close();
                }
            }
            catch
            {
            }

            return connected;
        }

        /// <summary>
        /// 获取头的下一行
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        private static string GetNextHeaderLine(NetworkStream stream)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                int readByte;
                while ((readByte = stream.ReadByte()) != '\n' && readByte != -1)
                {
                    if (readByte != '\r')
                        ms.WriteByte((byte)readByte);
                }
                if (ms.Length == 0)
                {
                    return string.Empty;
                }
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }
        //Nokia5700AP23.01/SymbianOS/9.1 Series60/3.0
        private const string postHeader = @"POST {0} HTTP/1.1
Host: {1}
User-Agent: Nokia5700AP23.01/SymbianOS/9.1 Series60/3.0
Accept: */*
Cache-Control: no-cache
Content-Length: {2}
Content-Type: application/x-www-form-urlencoded

{3}";

        private const string getHeader = @"GET {0} HTTP/1.1
Host: {1}
User-Agent: Nokia5700AP23.01/SymbianOS/9.1 Series60/3.0
Accept: */*
Accept-Encoding: gzip,deflate
Cache-Control: no-cache

";
    }
}
